<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>tiptap 自定义扩展 - itxst.com</title>
    <meta name="keywords" content="tiptap 自定义扩展" />
    <meta name="description" content="我们在使用web编辑器时往往需要 extensions 自定义扩展，因为如何一款web编辑器自带的扩展都不可能满足场景的需求，tiptap 可以这种个性化的需求有两种方法，一是按照官方的方法实现扩展，一种是自己写vue组件调用tiptap命令，这样也可以非常方便的集成到tiptap。" />
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <meta http-equiv="Content-Language" content="zh-CN">
    <link rel="shortcut icon" href="/img/favicon.ico" type="image/x-icon" />
    <link href="/css/zt.css?ver=1.6.6" rel="stylesheet" type="text/css" media="all" />
    <script type="text/javascript" language="javascript" src="/js/jquery.js?ver=1.6.6"></script>
    <script type="text/javascript" src="/js/highlight/highlight.min.js?ver=1.6.6"></script>
    <link rel="stylesheet" type="text/css" href="/js/highlight/styles/vs2015x.css?ver=1.6.6">
    <script type="text/javascript" language="javascript" src="/js/comm.js?ver=1.6.6"></script>
    <script type="text/javascript" language="javascript" src="/js/zt.js?ver=1.6.6"></script>
    <script type="text/javascript" charset="utf-8" src="/js/layer/layer.js?ver=1.6.6"></script>
    <link rel="alternate" media="only screen and(max-width: 640px)" href="http://m.itxst.com/tiptap/customextensions.html" >
    <!--[if lte IE 9]>
    <script src="/js/respond/respond.js?ver=1.6.6"></script>
    <![endif]-->
</head>
<body>
    <div class="body"  >
        <div class="header">
            <div class="naver">
                <div class="logo">
                    <a href="/"><img src="/img/logov31.png" /></a>
                </div>
                <div class="naver-left">
                 <a href="/tiptap/tutorial.html">tiptap 中文文档</a>
                </div>
                <div class="naver-search">
                    <div class="naver-search-txt">
                        <input type="text" id="keyword" placeholder="Please enter the keyword" data-topic="tiptap">
                    </div>
                    <div class="naver-search-btn"><a href="javascript:void(0)" onclick="Search()">Search</a></div>
                </div>
                 <div class="naver-right"> 
                        <a href="/ag-grid/tutorial.html">AG-GRID</a> 
                        <a href="/tiptap/tutorial.html">Tiptap</a> 
                        <a href="/css-flex/tutorial.html">CSS-FLEX</a> 
                        <a href="/Bootstrap-Table/QuickStart.html">Bootstrap-Table</a> 
                </div>
            </div>
            <div class="path">
                
            </div>
        </div>
        <div class="clearfix"></div>
        <div class="pagew">
        <div class="page" >
            <div class="page-body">
                <div class="content-detail">
                    <h1>tiptap 自定义扩展</h1>
               
               <p class="p">我们在使用<b>web编辑器</b>时往往需要<b>extensions</b>自定义扩展，因为如何一款web编辑器自带的扩展都不可能满足场景的需求，<b>tiptap</b>可以这种个性化的需求有两种方法，一是按照<b>官方方法</b>实现扩展，一种是自己写<b>vue组件</b>调用tiptap命令，这样也可以非常方便的集成到tiptap。</p><h2>扩展已有的扩展</h2><p class="pe"><b>tiptap</b>提供了非常多的扩展，当这些扩展无法满足你的需求时，你可以对它进行<b>再次扩展</b>，每个扩展都有一个<b>extend()</b>方法，该方法接受一个<b>object</b>，其中object包含您想要更改或添加的所有内容。下面代码演示了扩展<b>BulletList列扩展</b>，实现按下<b>Ctrl+L快捷键</b>把普通文本转成列</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// 1. 导入扩展
import BulletList from '@tiptap/extension-bullet-list'

// 2. 重写快捷键
const CustomBulletList = BulletList.extend({
  addKeyboardShortcuts() {
    return {
      'Mod-l': () =&gt; this.editor.commands.toggleBulletList(),
    }
  },
})

// 3. 注册扩展
new Editor({
  extensions: [
    CustomBulletList(),
    // …
  ],
})</code></pre><h2>name 扩展名</h2><p class="p">扩展名在很多地方被使用，使用不太容易改变名称，如果要更改现有扩展的名称，可以复制整个扩展并在所有情况下更改名称。扩展名也是JSON的一部分，如果你将编辑器内容存储为JSON，则也需要更改它的名称。</p><h2>priority 优先级</h2><p class="pe"><b>priority</b> 定义了注册扩展的顺序,扩展的默认优先级是100，这是大多数扩展的优先级，<b>值越大越先注册</b>。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import Link from '@tiptap/extension-link'

const CustomLink = Link.extend({
  priority: 1000,
})</code></pre><p class="p">扩展的注册顺序会影响,<b>Plugin order</b>和<b>Schema order</b><br/> &nbsp;<b>Link扩展</b>拥有更高的优先级，将把<b>&lt;strong&gt;&lt;a href=&quot;…&quot;&gt;Example&lt;/a&gt;&lt;/strong&gt; &nbsp;</b>呈现为<b>&lt;a href=&quot;…&quot;&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/a&gt;</b></p><h2>settings 配置</h2><p class="pe">对已有扩展进行再次封装时，你可以重新进行重写配置项，实现代码如下</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import Heading from '@tiptap/extension-heading'

const CustomHeading = Heading.extend({
  addOptions() {
    return {
      ...this.parent?.(),
      levels: [1, 2, 3],
    }
  },
})</code></pre><h2>storage 存储</h2><p class="pe">有些情况下你可能希望在扩展中存储一下数据，你可以通过<b>this.storage</b>访问</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Extension } from '@tiptap/core'

const CustomExtension = Extension.create({
  name: 'customExtension',
  addStorage() {
    return {
      awesomeness: 100,
    }
  },

  onUpdate() {
    this.storage.awesomeness += 1
  },
})</code></pre><p class="pe">除此之外，你也可以通过<b>editor.storage</b>访问，确保每个扩展的名称是唯一的</p><pre class="brush:js;toolbar:false"><code class="language-javascript">const editor = new Editor({
  extensions: [
    CustomExtension,
  ],
})

const awesomeness = editor.storage.customExtension.awesomeness;</code></pre><h2>schema</h2><p class="pe">Tiptap使用严格的<b>Schema</b>，Schema 配置内容的结构、嵌套、行为等。让我们来看看几个常见的用例,默认的<b>Blockquote扩展</b>可以包裹其他节点，比如标题，如果你想只允许段落，相应地设置<b>content</b>属性:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// Blockquotes must only include paragraphs
import Blockquote from '@tiptap/extension-blockquote'

const CustomBlockquote = Blockquote.extend({
  content: 'paragraph*',
})</code></pre><p class="pe">Schema 允许你的节点是<b>可拖拽</b>的，配置<b>draggable</b>选项的即可，默认为<b>false</b>，但你可以重写它。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// Draggable paragraphs
import Paragraph from '@tiptap/extension-paragraph'

const CustomParagraph = Paragraph.extend({
  draggable: true,
})</code></pre><h2>attributes 属性</h2><p class="pe">你可以使用<b>attributes</b>属性在内容中存储其他信息，比如你想扩展<b>Paragraph</b>节点，让它有不同的颜色:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">const CustomParagraph = Paragraph.extend({
  addAttributes() {
    // Return an object with attribute configuration
    return {
      color: {
        default: 'pink',
      },
    },
  },
})

// 输出结果:
// &lt;p color="pink"&gt;Example Text&lt;/p&gt;</code></pre><p class="pe">我们也可以使用<b>renderHTM</b>L实现内联样式属性。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">const CustomParagraph = Paragraph.extend({
  addAttributes() {
    return {
      color: {
        default: null,
        // Take the attribute values
        renderHTML: attributes =&gt; {
          // … and return an object with HTML attributes.
          return {
            style: `color: ${attributes.color}`,
          }
        },
      },
    }
  },
})

// 输出结果:
// &lt;p style="color: pink"&gt;Example Text&lt;/p&gt;</code></pre><p class="pe">您还可以控制从<b>HTML</b>中解析属性的方式，你可以将颜色存储在一个名为<b>data-color</b>的属性中(而不仅仅是color)。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">const CustomParagraph = Paragraph.extend({
  addAttributes() {
    return {
      color: {
        default: null,
        // Customize the HTML parsing (for example, to load the initial content)
        parseHTML: element =&gt; element.getAttribute('data-color'),
        // … and customize the HTML rendering.
        renderHTML: attributes =&gt; {
          return {
            'data-color': attributes.color,
            style: `color: ${attributes.color}`,
          }
        },
      },
    }
  },
})

// Result:
// &lt;p data-color="pink" style="color: pink"&gt;Example Text&lt;/p&gt;</code></pre><p class="pe">你可以使用<b>render: false</b>完全禁用属性的呈现,如果你想添加一个属性到一个扩展，并保留现有的属性，你可以通过<b>this.parent()</b>访问它们。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">const CustomTableCell = TableCell.extend({
  addAttributes() {
    return {
      ...this.parent?.(),
      myCustomAttribute: {
        // …
      },
    }
  },
})</code></pre><h2>global attributes</h2><p class="pe">属性可以同时应用到多个扩展。这对于文本对齐、行高、颜色、字体系列和其他样式相关属性非常有用。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Extension } from '@tiptap/core'

const TextAlign = Extension.create({
  addGlobalAttributes() {
    return [
      {
        // Extend the following extensions
        types: [
          'heading',
          'paragraph',
        ],
        // … with those attributes
        attributes: {
          textAlign: {
            default: 'left',
            renderHTML: attributes =&gt; ({
              style: `text-align: ${attributes.textAlign}`,
            }),
            parseHTML: element =&gt; element.style.textAlign || 'left',
          },
        },
      },
    ]
  },
})</code></pre><h2>render HTML</h2><p class="pe">使用<b>renderHTML</b>函数你可以将扩展渲染为HTML。我们将一个属性对象传递给它，其中包含所有本地属性、全局属性和配置的CSS类。下面是一个来自<b>Bold</b>扩展的例子:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">renderHTML({ HTMLAttributes }) {
  return ['strong', HTMLAttributes, 0]
}</code></pre><p class="pe">数组中的第一个值我HTML标签的名称。如果第2个元素是一个对象，它将被解释为一组属性，在此之后的任何元素都呈现为子元素。</p><p class="pe">数字0用来指示内容应该插入的位置，让我们看看带有两个嵌套标记的<b>CodeBlock</b>扩展的呈现:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">renderHTML({ HTMLAttributes }) {
  return ['pre', ['code', HTMLAttributes, 0]]
}</code></pre><p class="pe">如果你想在添加一些特定的属性，可以从<b>@tiptap/core</b>导入<b>mergeAttributes</b>:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { mergeAttributes } from '@tiptap/core'

// ...

renderHTML({ HTMLAttributes }) {
  return ['a', mergeAttributes(HTMLAttributes, { rel: this.options.rel }), 0]
}</code></pre><h2>parse HTML</h2><p class="pe">使用<b>parseHTML()</b>函数尝试从编辑器加载html文档，下面是 <b>Bold mark</b> 的简化示例:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">parseHTML() {
  return [
    {
      tag: 'strong',
    },
  ]
}</code></pre><p class="pe">这定义了一个将所有<b>&lt;strong&gt;</b>标签转换为<b>Bold标签</b>的规则，但你可以使用更高级的用法，下面是完整的例子:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">parseHTML() {
  return [
    // &lt;strong&gt;
    {
      tag: 'strong',
    },
    // &lt;b&gt;
    {
      tag: 'b',
      getAttrs: node =&gt; node.style.fontWeight !== 'normal' &amp;&amp; null,
    },
    // &lt;span style="font-weight: bold"&gt; and &lt;span style="font-weight: 700"&gt;
    {
      style: 'font-weight',
      getAttrs: value =&gt; /^(bold(er)?|[5-9]\d{2,})$/.test(value as string) &amp;&amp; null,
    },
  ]
}</code></pre><p class="pe">这将检查<b>&lt;strong&gt;</b>和<b>&lt;b&gt;</b>标记。如你所见，你可以选择性地传递一个<b>getAttrs</b>回调，以添加更复杂的检查。<br/><br/>在这个例子中，你可能已经注意到<b>getAttrs</b>函数有两个目的:</p><ul class=" list-paddingleft-2"><li><p>检查HTML属性以确定规则是否匹配</p></li><li><p>获取DOM Element并使用HTML属性来设置标记或节点属性</p></li></ul><pre class="brush:js;toolbar:false"><code class="language-javascript">parseHTML() {
  return [
    {
      tag: 'span',
      getAttrs: element =&gt; {
        // Check if the element has an attribute
        element.hasAttribute('style')
        // Get an inline style
        element.style.color
        // Get a specific attribute
        element.getAttribute('data-color')
      },
    },
  ]
}</code></pre><p class="pe">你可以返回一个对象，其中属性作为键，解析值用于设置<b>mark</b>或<b>node</b>属性。不过，我们建议在<b>addAttributes()</b>中使用<b>parseHTML</b>，更详细的信息请访问 <a href="https://prosemirror.net/docs/ref/#model.ParseRule" target="_blank">https://prosemirror.net/docs/ref/#model.ParseRule</a>。</p><h2>commands 命令</h2><p class="pe">在扩展中使用命令或添加一个Commands命令:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import Paragraph from '@tiptap/extension-paragraph'

const CustomParagraph = Paragraph.extend({
  addCommands() {
    return {
      paragraph: () =&gt; ({ commands }) =&gt; {
        return commands.setNode('paragraph')
      },
    }
  },
})</code></pre><h2>shortcuts 快捷键</h2><p class="pe">大多数核心的扩展都带有快捷键，你可以使用<b>addKeyboardShortcuts()</b>方法，覆盖预定义的快捷键:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// Change the bullet list keyboard shortcut
import BulletList from '@tiptap/extension-bullet-list'

const CustomBulletList = BulletList.extend({
  addKeyboardShortcuts() {
    return {
      'Mod-l': () =&gt; this.editor.commands.toggleBulletList(),
    }
  }
})</code></pre><h2>input rules 输入规则</h2><p class="pe">使用输入规则<b>Input rules</b>，你可以定义<b>正则表达式</b>来侦听用户输入，比如将文本(c)转换为©字符。<b>mark</b>标记使用<b>markInputRule</b>函数，<b>node</b>节点使用<b>nodeInputRule</b>函数。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// Use the ~single tilde~ markdown shortcut
import Strike from '@tiptap/extension-strike'
import { markInputRule } from '@tiptap/core'

// Default:
// const inputRegex = /(?:^|\s)((?:~~)((?:[^~]+))(?:~~))$/

// New:
const inputRegex = /(?:^|\s)((?:~)((?:[^~]+))(?:~))$/

const CustomStrike = Strike.extend({
  addInputRules() {
    return [
      markInputRule({
        find: inputRegex,
        type: this.type,
      }),
    ]
  }
})</code></pre><h2>paste rules 粘贴规则</h2><p class="pe">粘贴规则的工作原理与输入规则类似(见上文)，应用于粘贴的内容。
正则表达式中有一个微小的区别。输入规则通常以$ 符号结束(这意味着“断言在一行末尾的位置”)，粘贴规则通常会查看所有内容，并且没有$ 符号，如下面的示例所示。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// Check pasted content for the ~single tilde~ markdown syntax
import Strike from '@tiptap/extension-strike'
import { markPasteRule } from '@tiptap/core'

// Default:
// const pasteRegex = /(?:^|\s)((?:~~)((?:[^~]+))(?:~~))/g

// New:
const pasteRegex = /(?:^|\s)((?:~)((?:[^~]+))(?:~))/g

const CustomStrike = Strike.extend({
  addPasteRules() {
    return [
      markPasteRule({
        find: pasteRegex,
        type: this.type,
      }),
    ]
  }
})</code></pre><h2>events 事件</h2><p class="pe">你可以将事件监听器移动到单独的扩展中，下面代码是一个所有事件监听器的例子:</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Extension } from '@tiptap/core'

const CustomExtension = Extension.create({
  onCreate() {
    // 编辑器初始化完成
  },
  onUpdate() {
    // 文档内容更新事件
  },
  onSelectionUpdate({ editor }) {
    // 选中内容改变
  },
  onTransaction({ transaction }) {
    // 编辑器状态更改事件 The editor state has changed.
  },
  onFocus({ event }) {
    // 编辑器获得焦点事件
  },
  onBlur({ event }) {
    // 编辑器失去焦点事件
  },
  onDestroy() {
    // 编辑器销毁事件
  },
})</code></pre><h2>this 对象</h2><p class="pe">下面代码是 <b>this</b> 对象的属性列表。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">// 扩展名称 'bulletList'
this.name

// 编辑器实例
this.editor

// ProseMirror type
this.type

// 所有的设置
this.options

// Everything that’s in the extended extension
this.parent</code></pre><h2>ProseMirror 插件</h2><p class="p">因为tiptap建立在<b>ProseMirror</b>之上所以我们可以用<b>addProseMirrorPlugins</b>去封装ProseMirror插件。</p><p class="pe">Existing plugins 封装已存在的ProseMirror插件</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { history } from '@tiptap/pm/history'

const History = Extension.create({
  addProseMirrorPlugins() {
    return [
      history(),
      // …
    ]
  },
})</code></pre><p class="pe">访问<b>ProseMirror API</b></p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Extension } from '@tiptap/core'
import { Plugin, PluginKey } from '@tiptap/pm/state'

export const EventHandler = Extension.create({
  name: 'eventHandler',
  addProseMirrorPlugins() {
    return [
      new Plugin({
        key: new PluginKey('eventHandler'),
        props: {
          handleClick(view, pos, event) { /* … */ },
          handleDoubleClick(view, pos, event) { /* … */ },
          handlePaste(view, event, slice) { /* … */ },
          // … and many, many more.
          // Here is the full list: https://prosemirror.net/docs/ref/#view.EditorProps
        },
      }),
    ]
  },
})</code></pre><h2>Node views 节点视图</h2><p class="p">对于高级用例，你可能需要在节点内执行<b>JavaScript</b>，例如围绕图片呈现复杂的界面，它很强大，但也很复杂。简而言之，你需要返回一个<b>父DOM元素</b>和一个<b>子DOM元素</b>，下面个简化的例子:</p><pre class="brush:js;toolbar:false"><code class="language-javascript"><code class="language-javascript">import Image from '@tiptap/extension-image'

const CustomImage = Image.extend({
  addNodeView() {
    return () =&gt; {
      const container = document.createElement('div')

      container.addEventListener('click', event =&gt; {
        alert('clicked on the container')
      })

      const content = document.createElement('div')
      container.append(content)


      return {
        dom: container,
        contentDOM: content,
      }
    }
  },
})</code></code></pre><h2>创建一个新扩展</h2><p class="p">当现有扩展无法满足你的需求时，你可以创建自己的扩展，它与上面描述的扩展现有的扩展的语法相同。</p><pre class="brush:js;toolbar:false"><code class="language-javascript"><code class="language-javascript">import Image from '@tiptap/extension-image'

const CustomImage = Image.extend({
  addNodeView() {
    return () =&gt; {
      const container = document.createElement('div')

      container.addEventListener('click', event =&gt; {
        alert('clicked on the container')
      })

      const content = document.createElement('div')
      container.append(content)


      return {
        dom: container,
        contentDOM: content,
      }
    }
  },
})</code></code></pre><p><strong>Create a node 创建节点</strong></p><p class="pe">如果将文档看作树，那么<b>node</b>节点只是树中的一种内容类型。可以学习 <b>Paragraph</b> 、<b>Heading</b> 或 <b>CodeBlock</b>扩展</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Node } from '@tiptap/core'

const CustomNode = Node.create({
  name: 'customNode',

  // Your code goes here.
})</code></pre><p><strong>Create a mark 创建标记</strong></p><p class="pe">你可以对<b>Node节点</b>添加一个或多个标记<b>Mark</b>，例如添加内联样式Style，你可以学习例子 Bold、Italic 或 Highlight。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Mark } from '@tiptap/core'

const CustomMark = Mark.create({
  name: 'customMark',

  // Your code goes here.
})</code></pre><p><strong>Create an extension 创建新扩展</strong></p><p class="pe">你可以通过<b>TextAlign</b>扩展学习如何创建一个新扩展。</p><pre class="brush:js;toolbar:false"><code class="language-javascript">import { Extension } from '@tiptap/core'

const CustomExtension = Extension.create({
  name: 'customExtension',

  // Your code goes here.
})</code></pre>
 
               <h2>
    下载教程 Demo
</h2>
<p class="pe">
   本教程<b>Demo</b>的源码点击这里下载，<a href="https://img1.itxst.com/8/c/8c32fcdc12cb8847c62e405be8a73835.zip" target="_blank" textvalue="Tiptap Demo">Tiptap Demo</a>，下载完成后运行<b>npm i</b>初始化依赖包。
</p>
                </div>
                <div class="content-r">   <a href="/tiptap/tutorial.html" target="_self">
                     <img src="https://img1.itxst.com/0/9/09355b3592a0c16799b504a9f2a70303.png" alt="tiptap 中文文档" />
                    </a>                                                <a href="//www.itxst.com/vue-draggable/tutorial.html" target="_blank">
                                <img src="//img1.itxst.com/b/f/bf9af8368dfac84cd703ef54e1e89d14.png" alt="vue.draggable" />
                            </a>
 
                </div>
            </div>
            <div class="home-menu scroll">
                <div class="tree">
      <a data-level="1" class="leve-1   doc-1   " href="/tiptap/tutorial.html" title="tiptap 中文文档">快速入门</a>
      <a data-level="1" class="leve-1    arrow-2" href="/tiptap/configuration.html" title="Guide 向导">Guide 向导</a>
      <a data-level="2" class="leve-2   doc-1   " href="/tiptap/configuration.html" title="Tiptap 编辑器 Configuration 配置">configuration 配置</a>
      <a data-level="2" class="leve-2   doc-1   " href="/tiptap/roseMirrorapi.html" title="ProseMirror  API">prosemirror  api</a>
      <a data-level="2" class="leve-2   doc-1   " href="/tiptap/menus.html" title="tiptap menus 菜单">menus 菜单</a>
      <a data-level="2" class="leve-2   doc-1   " href="/tiptap/styling.html" title="Styling Titpap 样式">styling 样式</a>
      <a data-level="2" class="leve-2   doc-1   " href="/tiptap/output.html" title="Titpap Output 输出格式">output 输出格式</a>
      <a data-level="2" class="leve-2   doc-1   " href="/tiptap/collaborative.html" title="tiptap collaborative 实时协作">collaborative 实时协作</a>
      <a data-level="2" class="leve-2   doc-1    doc-2 " href="/tiptap/customextensions.html" title="tiptap 自定义扩展">extensions 自定义扩展</a>
      <a data-level="1" class="leve-1    arrow-1" href="/tiptap/api.html" title="tiptap api 列表">API 列表</a>
                 </div>
                 <div  class="clearfix"></div>
            </div>
        </div>
        <div class="clearfix"></div>
           <div class="footer">
© 2023 itxst.com All rights reserved.
</div>

<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?7e15ed96eb8133218e99de8bc1f5cb61";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();
</script>
       </div>
    </div> 
</body>
</html>
